﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Windows.Threading;
using DataStore;
using DataStore.Domain;
using DataStore.Repositories;
using Infrastructure.CurrentData;
using Microsoft.Practices.Composite.Events;

namespace Infrastructure.ViewModels
{
    /// <summary>
    /// AllCovers viewmodel
    /// </summary>
    public class AllCoversViewModel : DataModel
    {
        readonly ObservableCollection<CoverViewModel> _covers = new ObservableCollection<CoverViewModel>();

        /// <summary>
        /// Gets the covers.
        /// </summary>
        /// <value>The covers.</value>
        public ObservableCollection<CoverViewModel> Covers
        {
            get
            {
                VerifyCalledOnUIThread();
                return _covers;
            }
            
        }

        /// <summary>
        /// Gets the front covers.
        /// </summary>
        /// <value>The front covers.</value>
        public IEnumerable<CoverViewModel> FrontCovers
        {
            get
            {
                VerifyCalledOnUIThread();
                var covers = from c in Covers
                             where c.Type == CoverType.Front
                             select c;
                return covers;
            }
        }

        /// <summary>
        /// Gets the back covers.
        /// </summary>
        /// <value>The back covers.</value>
        public IEnumerable<CoverViewModel> BackCovers
        {
            get
            {
                VerifyCalledOnUIThread();
                var covers = from c in Covers
                             where c.Type == CoverType.Back
                             select c;
                return covers;
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="AllCoversViewModel"/> class.
        /// </summary>
        /// <param name="eventAggregator">The event aggregator.</param>
        public AllCoversViewModel(IEventAggregator eventAggregator) : base(eventAggregator)
        {
            State = ModelState.Fetching;

            RefreshCovers();
        }

        /// <summary>
        /// Refreshes the covers.
        /// </summary>
        void RefreshCovers()
        {
            if (!ThreadPool.QueueUserWorkItem(FetchCoversCallback))
            {
                State = ModelState.Invalid;
            }
        }

        /// <summary>
        /// Fetches the covers callback.
        /// </summary>
        /// <param name="state">The state.</param>
        void FetchCoversCallback(object state)
        {
            IDatabase database = Current.Container.Resolve<IDatabase>();
            var unitOfWork = database.CreateUnitOfWork();

            try
            {
                IRepository<Cover> repository = new CoverRepository(unitOfWork);
                var covers = repository.All;

                Dispatcher.BeginInvoke(
                    new ThreadStart(delegate
                                        {
                                            Covers.Clear();
                                            foreach (var cover in covers)
                                            {
                                                Covers.Add(new CoverViewModel(EventAggregator, cover));
                                            }

                                            unitOfWork.Dispose();

                                            State = ModelState.Active;


                                            OnPropertyChanged("Covers");
                                            OnPropertyChanged("FrontCovers");
                                            OnPropertyChanged("BackCovers");

                                            OnLoaded(this, EventArgs.Empty);
                                        }),
                    DispatcherPriority.ApplicationIdle);
            }
            catch (Exception e)
            {
                Log.Error("Failed to load Covers", e);

                unitOfWork.Dispose();
                Dispatcher.BeginInvoke(
                    new ThreadStart(delegate
                                        {
                                            State = ModelState.Invalid;
                                            OnLoaded(this, EventArgs.Empty);

                                            OnPropertyChanged("Covers");
                                            OnPropertyChanged("FrontCovers");
                                            OnPropertyChanged("BackCovers");
                                        }),
                    DispatcherPriority.ApplicationIdle);

            }
        }
    }
}